/*     */ package com.zimbra.cs.service.mail;
/*     */ 
/*     */ import com.zimbra.client.ZMailbox;
/*     */ import com.zimbra.client.ZMailbox.Options;
/*     */ import com.zimbra.client.ZMailbox.ZGetMiniCalResult;
/*     */ import com.zimbra.client.ZMailbox.ZMiniCalError;
/*     */ import com.zimbra.common.account.Key.AccountBy;
/*     */ import com.zimbra.common.calendar.ICalTimeZone;
/*     */ import com.zimbra.common.calendar.WellKnownTimeZones;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.AccountServiceException;
/*     */ import com.zimbra.cs.account.AuthToken;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.mailbox.Folder;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.MailboxManager;
/*     */ import com.zimbra.cs.mailbox.Mountpoint;
/*     */ import com.zimbra.cs.mailbox.OperationContext;
/*     */ import com.zimbra.cs.mailbox.calendar.Util;
/*     */ import com.zimbra.cs.mailbox.calendar.cache.CalSummaryCache;
/*     */ import com.zimbra.cs.mailbox.calendar.cache.CalSummaryCache.CalendarDataResult;
/*     */ import com.zimbra.cs.mailbox.calendar.cache.CalendarCacheManager;
/*     */ import com.zimbra.cs.mailbox.calendar.cache.CalendarData;
/*     */ import com.zimbra.cs.mailbox.calendar.cache.CalendarItemData;
/*     */ import com.zimbra.cs.mailbox.calendar.cache.FullInstanceData;
/*     */ import com.zimbra.cs.mailbox.calendar.cache.InstanceData;
/*     */ import com.zimbra.cs.service.util.ItemId;
/*     */ import com.zimbra.cs.service.util.ItemIdFormatter;
/*     */ import com.zimbra.cs.util.AccountUtil;
/*     */ import com.zimbra.soap.ZimbraSoapContext;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Calendar;
/*     */ import java.util.GregorianCalendar;
/*     */ import java.util.HashMap;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Map.Entry;
/*     */ import java.util.Set;
/*     */ import java.util.TreeSet;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class GetMiniCal
/*     */   extends CalendarRequest
/*     */ {
/*     */   public Element handle(Element request, Map<String, Object> context)
/*     */     throws ServiceException
/*     */   {
/*  82 */     ZimbraSoapContext zsc = getZimbraSoapContext(context);
/*  83 */     Mailbox mbox = getRequestedMailbox(zsc);
/*  84 */     Account authAcct = getAuthenticatedAccount(zsc);
/*  85 */     OperationContext octxt = getOperationContext(zsc, context);
/*  86 */     Element response = getResponseElement(zsc);
/*     */     
/*  88 */     long rangeStart = request.getAttributeLong("s");
/*  89 */     long rangeEnd = request.getAttributeLong("e");
/*     */     
/*  91 */     List<ItemId> folderIids = new ArrayList();
/*  92 */     for (Iterator<Element> foldersIter = request.elementIterator("folder"); foldersIter.hasNext();) {
/*  93 */       Element fElem = (Element)foldersIter.next();
/*  94 */       ItemId iidFolder = new ItemId(fElem.getAttribute("id"), zsc);
/*  95 */       folderIids.add(iidFolder);
/*     */     }
/*     */     
/*  98 */     ICalTimeZone tz = parseTimeZone(request);
/*  99 */     if (tz == null)
/* 100 */       tz = Util.getAccountTimeZone(authAcct);
/* 101 */     TreeSet<String> busyDates = new TreeSet();
/*     */     
/* 103 */     Provisioning prov = Provisioning.getInstance();
/* 104 */     MailboxManager mboxMgr = MailboxManager.getInstance();
/* 105 */     Server localServer = prov.getLocalServer();
/*     */     
/* 107 */     ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
/* 108 */     Map<ItemId, Resolved> resolved = resolveMountpoints(octxt, mbox, folderIids);
/* 109 */     Map<ItemId, ItemId> reverseMap = new HashMap();
/* 110 */     for (Map.Entry<ItemId, Resolved> entry : resolved.entrySet()) {
/* 111 */       ItemId requestedIid = (ItemId)entry.getKey();
/* 112 */       Resolved res = (Resolved)entry.getValue();
/* 113 */       if (res.error == null) {
/* 114 */         reverseMap.put(res.iid, requestedIid);
/*     */       } else {
/* 116 */         addError(response, ifmt.formatItemId(requestedIid), res.error.getCode(), res.error.getMessage());
/*     */       }
/*     */     }
/* 119 */     Map<Server, Map<String, List<Integer>>> groupedByServer = Search.groupByServer(groupFoldersByAccount(resolved));
/*     */     
/*     */ 
/*     */ 
/* 123 */     if (LC.calendar_cache_enabled.booleanValue()) {
/* 124 */       CalSummaryCache calCache = CalendarCacheManager.getInstance().getSummaryCache();
/* 125 */       Calendar cal = new GregorianCalendar(tz);
/* 126 */       Iterator<Map.Entry<Server, Map<String, List<Integer>>>> serverIter = groupedByServer.entrySet().iterator();
/* 127 */       while (serverIter.hasNext()) {
/* 128 */         Map.Entry<Server, Map<String, List<Integer>>> serverMapEntry = (Map.Entry)serverIter.next();
/* 129 */         Map<String, List<Integer>> accountFolders = (Map)serverMapEntry.getValue();
/*     */         
/* 131 */         Iterator<Map.Entry<String, List<Integer>>> acctIter = accountFolders.entrySet().iterator();
/* 132 */         while (acctIter.hasNext()) {
/* 133 */           Map.Entry<String, List<Integer>> acctEntry = (Map.Entry)acctIter.next();
/* 134 */           String acctId = (String)acctEntry.getKey();
/* 135 */           List<Integer> folderIds = (List)acctEntry.getValue();
/*     */           
/* 137 */           for (Iterator<Integer> iterFolderId = folderIds.iterator(); iterFolderId.hasNext();) {
/* 138 */             int folderId = ((Integer)iterFolderId.next()).intValue();
/*     */             try {
/* 140 */               CalSummaryCache.CalendarDataResult result = calCache.getCalendarSummary(octxt, acctId, folderId, MailItem.Type.APPOINTMENT, rangeStart, rangeEnd, true);
/*     */               
/* 142 */               if (result != null)
/*     */               {
/* 144 */                 iterFolderId.remove();
/* 145 */                 addBusyDates(cal, result.data, rangeStart, rangeEnd, busyDates);
/*     */               }
/*     */             } catch (ServiceException e) {
/* 148 */               iterFolderId.remove();
/* 149 */               ItemId iid = new ItemId(acctId, folderId);
/* 150 */               ItemId reqIid = (ItemId)reverseMap.get(iid);
/* 151 */               if (reqIid != null) {
/* 152 */                 ZimbraLog.calendar.warn("Error accessing calendar folder " + ifmt.formatItemId(reqIid), e);
/* 153 */                 addError(response, ifmt.formatItemId(reqIid), e.getCode(), e.getMessage());
/*     */               } else {
/* 155 */                 ZimbraLog.calendar.warn("Error accessing calendar folder; resolved id=" + ifmt.formatItemId(iid) + " (missing reverse mapping)", e);
/*     */                 
/* 157 */                 addError(response, ifmt.formatItemId(iid), e.getCode(), e.getMessage());
/*     */               }
/*     */             }
/*     */           }
/* 161 */           if (folderIds.isEmpty())
/* 162 */             acctIter.remove();
/*     */         }
/* 164 */         if (accountFolders.isEmpty()) {
/* 165 */           serverIter.remove();
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 170 */     for (Map.Entry<Server, Map<String, List<Integer>>> serverMapEntry : groupedByServer.entrySet()) {
/* 171 */       Server server = (Server)serverMapEntry.getKey();
/* 172 */       Map<String, List<Integer>> accountFolders = (Map)serverMapEntry.getValue();
/* 173 */       String acctId; Mailbox targetMbox; Iterator i$; if (server.equals(localServer)) {
/* 174 */         for (Map.Entry<String, List<Integer>> entry : accountFolders.entrySet()) {
/* 175 */           acctId = (String)entry.getKey();
/* 176 */           List<Integer> folderIds = (List)entry.getValue();
/* 177 */           Account targetAcct = prov.get(Key.AccountBy.id, acctId);
/* 178 */           if (targetAcct == null) {
/* 179 */             ZimbraLog.calendar.warn("Skipping unknown account " + acctId + " during minical search");
/*     */           }
/*     */           else {
/* 182 */             targetMbox = mboxMgr.getMailboxByAccount(targetAcct);
/* 183 */             for (i$ = folderIds.iterator(); i$.hasNext();) { int folderId = ((Integer)i$.next()).intValue();
/*     */               try {
/* 185 */                 doLocalFolder(octxt, tz, targetMbox, folderId, rangeStart, rangeEnd, busyDates);
/*     */               } catch (ServiceException e) {
/* 187 */                 ItemId iid = new ItemId(acctId, folderId);
/* 188 */                 ItemId reqIid = (ItemId)reverseMap.get(iid);
/* 189 */                 if (reqIid != null) {
/* 190 */                   ZimbraLog.calendar.warn("Error accessing calendar folder " + ifmt.formatItemId(reqIid), e);
/* 191 */                   addError(response, ifmt.formatItemId(reqIid), e.getCode(), e.getMessage());
/*     */                 } else {
/* 193 */                   ZimbraLog.calendar.warn("Error accessing calendar folder; resolved id=" + ifmt.formatItemId(iid) + " (missing reverse mapping)", e);
/*     */                   
/* 195 */                   addError(response, ifmt.formatItemId(iid), e.getCode(), e.getMessage());
/*     */                 }
/*     */               }
/*     */             }
/*     */           }
/*     */         }
/* 201 */       } else { String nominalTargetAcctId = null;
/* 202 */         List<String> folderList = new ArrayList();
/* 203 */         for (Map.Entry<String, List<Integer>> entry : accountFolders.entrySet()) {
/* 204 */           String acctId = (String)entry.getKey();
/* 205 */           if (nominalTargetAcctId == null)
/* 206 */             nominalTargetAcctId = acctId;
/* 207 */           ifmtRemote = new ItemIdFormatter(authAcct.getId(), acctId, false);
/* 208 */           List<Integer> folderIds = (List)entry.getValue();
/* 209 */           for (i$ = folderIds.iterator(); i$.hasNext();) { int folderId = ((Integer)i$.next()).intValue();
/* 210 */             folderList.add(ifmtRemote.formatItemId(folderId)); } }
/*     */         ItemIdFormatter ifmtRemote;
/*     */         Iterator i$;
/* 213 */         doRemoteFolders(zsc, nominalTargetAcctId, folderList, rangeStart, rangeEnd, busyDates, response, reverseMap, ifmt);
/*     */       }
/*     */     }
/*     */     
/* 217 */     for (String datestamp : busyDates) {
/* 218 */       Element dateElem = response.addElement("date");
/* 219 */       dateElem.setText(datestamp);
/*     */     }
/*     */     
/* 222 */     return response;
/*     */   }
/*     */   
/*     */   private static void addBusyDates(Calendar cal, CalendarData calData, long rangeStart, long rangeEnd, Set<String> busyDates) throws ServiceException
/*     */   {
/* 227 */     for (Iterator<CalendarItemData> itemIter = calData.calendarItemIterator(); itemIter.hasNext();) {
/* 228 */       item = (CalendarItemData)itemIter.next();
/* 229 */       for (instIter = item.instanceIterator(); instIter.hasNext();) {
/* 230 */         InstanceData inst = (InstanceData)instIter.next();
/*     */         
/* 232 */         String partStat = inst.getPartStat();
/* 233 */         if (partStat == null)
/* 234 */           partStat = item.getDefaultData().getPartStat();
/* 235 */         if (!"DE".equals(partStat))
/*     */         {
/* 237 */           Long start = inst.getDtStart();
/* 238 */           if (start != null) {
/* 239 */             String datestampStart = getDatestamp(cal, start.longValue());
/* 240 */             busyDates.add(datestampStart);
/* 241 */             Long duration = inst.getDuration();
/* 242 */             if (duration != null) {
/* 243 */               long end = start.longValue() + duration.longValue();
/* 244 */               String datestampEnd = getDatestamp(cal, end);
/* 245 */               busyDates.add(datestampEnd);
/*     */             }
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */     CalendarItemData item;
/*     */     Iterator<InstanceData> instIter; }
/*     */   
/* 254 */   private static void doLocalFolder(OperationContext octxt, ICalTimeZone tz, Mailbox mbox, int folderId, long rangeStart, long rangeEnd, Set<String> busyDates) throws ServiceException { Calendar cal = new GregorianCalendar(tz);
/* 255 */     CalSummaryCache.CalendarDataResult result = mbox.getCalendarSummaryForRange(octxt, folderId, MailItem.Type.APPOINTMENT, rangeStart, rangeEnd);
/*     */     
/* 257 */     if (result != null) {
/* 258 */       addBusyDates(cal, result.data, rangeStart, rangeEnd, busyDates);
/*     */     }
/*     */   }
/*     */   
/*     */   private static void doRemoteFolders(ZimbraSoapContext zsc, String remoteAccountId, List<String> remoteFolders, long rangeStart, long rangeEnd, Set<String> busyDates, Element response, Map<ItemId, ItemId> reverseIidMap, ItemIdFormatter ifmt)
/*     */   {
/*     */     try
/*     */     {
/* 266 */       Account target = Provisioning.getInstance().get(Key.AccountBy.id, remoteAccountId);
/* 267 */       if (target == null)
/* 268 */         throw AccountServiceException.NO_SUCH_ACCOUNT(remoteAccountId);
/* 269 */       AuthToken authToken = AuthToken.getCsrfUnsecuredAuthToken(zsc.getAuthToken());
/* 270 */       ZMailbox.Options zoptions = new ZMailbox.Options(authToken.toZAuthToken(), AccountUtil.getSoapUri(target));
/* 271 */       zoptions.setTargetAccount(remoteAccountId);
/* 272 */       zoptions.setTargetAccountBy(Key.AccountBy.id);
/* 273 */       zoptions.setNoSession(true);
/* 274 */       ZMailbox zmbx = ZMailbox.getMailbox(zoptions);
/* 275 */       String[] remoteIds = new String[remoteFolders.size()];
/* 276 */       for (int i = 0; i < remoteIds.length; i++) remoteIds[i] = ((String)remoteFolders.get(i)).toString();
/* 277 */       ZMailbox.ZGetMiniCalResult result = zmbx.getMiniCal(rangeStart, rangeEnd, remoteIds);
/* 278 */       Set<String> dates = result.getDates();
/* 279 */       if (dates != null) {
/* 280 */         for (String datestamp : dates) {
/* 281 */           busyDates.add(datestamp);
/*     */         }
/*     */       }
/* 284 */       List<ZMailbox.ZMiniCalError> errors = result.getErrors();
/* 285 */       if (errors != null) {
/* 286 */         for (ZMailbox.ZMiniCalError error : errors) {
/*     */           try {
/* 288 */             ItemId iid = new ItemId(error.getFolderId(), zsc);
/* 289 */             ItemId reqIid = (ItemId)reverseIidMap.get(iid);
/* 290 */             String fid = ifmt.formatItemId(reqIid != null ? reqIid : iid);
/* 291 */             addError(response, fid, error.getErrCode(), error.getErrMsg());
/*     */           } catch (ServiceException e) {}
/*     */         }
/*     */       }
/*     */     } catch (ServiceException e) {
/* 296 */       ZimbraLog.calendar.warn("Error making remote GetMiniCalRequest", e);
/*     */       
/* 298 */       for (String remoteFid : remoteFolders) {
/*     */         try {
/* 300 */           ItemId iid = new ItemId(remoteFid, zsc);
/* 301 */           ItemId reqIid = (ItemId)reverseIidMap.get(iid);
/* 302 */           String fid = ifmt.formatItemId(reqIid != null ? reqIid : iid);
/* 303 */           addError(response, fid, e.getCode(), e.getMessage());
/*     */         } catch (ServiceException e2) {}
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private static String getDatestamp(Calendar cal, long millis) {
/* 310 */     cal.setTimeInMillis(millis);
/* 311 */     int year = cal.get(1);
/* 312 */     int month = cal.get(2) + 1;
/* 313 */     int day = cal.get(5);
/* 314 */     return Integer.toString(year * 10000 + month * 100 + day);
/*     */   }
/*     */   
/*     */   private static ICalTimeZone parseTimeZone(Element request) throws ServiceException {
/* 318 */     Element tzElem = request.getOptionalElement("tz");
/* 319 */     if (tzElem != null) {
/* 320 */       String tzid = tzElem.getAttribute("id", null);
/* 321 */       if (tzid != null) {
/* 322 */         ICalTimeZone knownTZ = WellKnownTimeZones.getTimeZoneById(tzid);
/* 323 */         if (knownTZ != null) {
/* 324 */           return knownTZ;
/*     */         }
/*     */       }
/*     */       
/* 328 */       String stdOffset = tzElem.getAttribute("stdoff", null);
/* 329 */       if (stdOffset == null) {
/* 330 */         throw ServiceException.INVALID_REQUEST("Unknown TZ: \"" + tzid + "\" and no " + "stdoff" + " specified", null);
/*     */       }
/*     */       
/* 333 */       return CalendarUtils.parseTzElement(tzElem);
/*     */     }
/* 335 */     return null;
/*     */   }
/*     */   
/*     */   private static class Resolved {
/*     */     public ItemId iid;
/*     */     public ServiceException error;
/*     */     
/*     */     Resolved(ItemId iid, ServiceException e) {
/* 343 */       this.iid = iid;
/* 344 */       this.error = e;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private static Map<ItemId, Resolved> resolveMountpoints(OperationContext octxt, Mailbox mbox, List<ItemId> folderIids)
/*     */   {
/* 352 */     Map<ItemId, Resolved> result = new HashMap();
/* 353 */     for (ItemId iidFolder : folderIids) {
/* 354 */       String targetAccountId = iidFolder.getAccountId();
/* 355 */       int folderId = iidFolder.getId();
/*     */       try {
/* 357 */         ServiceException error = null;
/* 358 */         if (mbox.getAccountId().equals(targetAccountId)) {
/* 359 */           boolean isMountpoint = true;
/* 360 */           int hopCount = 0;
/*     */           
/* 362 */           while ((isMountpoint) && (hopCount < 5)) {
/* 363 */             Folder folder = mbox.getFolderById(octxt, folderId);
/* 364 */             isMountpoint = folder instanceof Mountpoint;
/* 365 */             if (isMountpoint) {
/* 366 */               Mountpoint mp = (Mountpoint)folder;
/* 367 */               folderId = mp.getRemoteId();
/* 368 */               if (!mp.isLocal())
/*     */               {
/* 370 */                 targetAccountId = mp.getOwnerId();
/* 371 */                 Account targetAcct = Provisioning.getInstance().get(Key.AccountBy.id, targetAccountId);
/* 372 */                 if (targetAcct != null) break;
/* 373 */                 error = AccountServiceException.NO_SUCH_ACCOUNT(targetAccountId); break;
/*     */               }
/*     */               
/* 376 */               hopCount++;
/*     */             }
/*     */           }
/* 379 */           if (hopCount >= 5)
/* 380 */             error = MailServiceException.TOO_MANY_HOPS(iidFolder);
/*     */         }
/* 382 */         result.put(iidFolder, new Resolved(new ItemId(targetAccountId, folderId), error));
/*     */       } catch (ServiceException e) {
/* 384 */         ItemIdFormatter ifmt = new ItemIdFormatter();
/* 385 */         ZimbraLog.calendar.warn("Error resolving calendar folder " + ifmt.formatItemId(iidFolder), e);
/* 386 */         result.put(iidFolder, new Resolved(new ItemId(targetAccountId, folderId), e));
/*     */       }
/*     */     }
/* 389 */     return result;
/*     */   }
/*     */   
/*     */   private static Map<String, List<Integer>> groupFoldersByAccount(Map<ItemId, Resolved> map) {
/* 393 */     Map<String, List<Integer>> foldersMap = new HashMap();
/* 394 */     for (Map.Entry<ItemId, Resolved> entry : map.entrySet()) {
/* 395 */       Resolved res = (Resolved)entry.getValue();
/* 396 */       if (res.error == null) {
/* 397 */         List<Integer> folderList = (List)foldersMap.get(res.iid.getAccountId());
/* 398 */         if (folderList == null) {
/* 399 */           folderList = new ArrayList();
/* 400 */           foldersMap.put(res.iid.getAccountId(), folderList);
/*     */         }
/* 402 */         folderList.add(Integer.valueOf(res.iid.getId()));
/*     */       }
/*     */     }
/* 405 */     return foldersMap;
/*     */   }
/*     */   
/*     */   private static void addError(Element parent, String folderId, String errcode, String errmsg) {
/* 409 */     Element errorElem = parent.addElement("error");
/* 410 */     errorElem.addAttribute("id", folderId);
/* 411 */     errorElem.addAttribute("code", errcode);
/* 412 */     errorElem.setText(errmsg);
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/service/mail/GetMiniCal.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */